package com.jt808.decode.utils;

import com.jt808.decode.constant.Jt808Constant;
import com.jt808.decode.model.CommandParams;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

/**
 * Public Method Class
 * @date 20230302
 */
@Slf4j
public class CommonUtil {
    /**
     * XOR every byte
     *
     * @param buf
     * @return
     */
    public static int xor(ByteBuf buf) {
        int checksum = 0;
        while (buf.readableBytes() > 0) {
            checksum ^= buf.readUnsignedByte();
        }
        return checksum;
    }

    /**
     * Hexadecimal to byte array
     * @param hex
     * @return
     */
    public static byte[] hexStr2Byte(String hex) {
        ByteBuffer bf = ByteBuffer.allocate(hex.length() / 2);
        for (int i = 0; i < hex.length(); i++) {
            String hexStr = hex.charAt(i) + "";
            i++;
            hexStr += hex.charAt(i);
            byte b = (byte) Integer.parseInt(hexStr, 16);
            bf.put(b);
        }
        return bf.array();
    }

    /**
     * Convert gnss time
     *
     * @param bcdTimeStr
     * @return
     */
    public static ZonedDateTime parseBcdTime(String bcdTimeStr) {
        if(bcdTimeStr.equals("000000000000")){
            bcdTimeStr="000101000000";
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmss");
        LocalDateTime localDateTime = LocalDateTime.parse(bcdTimeStr, formatter);
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneOffset.UTC);
        return zonedDateTime;
    }

    /**
     * parse temperature
     * @param temperatureInt
     * @return
     */
    public static double parseTemperature(int temperatureInt) {
        if (temperatureInt == 0x7FFF) {
            return -1000.0;
        }
        double temperature = ((short) (temperatureInt << 4) >> 4) * 0.1;
        if ((temperatureInt >> 12) > 0) {
            temperature = -temperature;
        }
        return temperature;
    }

    /**
     * Adding colons between MAC addresses
     * @param input
     * @return
     */
    public static String handleMacAddress(String input){
        return input.replaceAll("..(?!$)", "$0:");
    }

    /**
     * ByteBuf reads GBK string
     *
     * @param buf
     * @param len
     * @return
     */
    public static String readGbkString(ByteBuf buf, int len) {
        return buf.readCharSequence(len, Charset.forName("GBK")).toString().trim();
    }
    /**
     * Terminal number to byte[]
     * @param terminalNum
     * @return
     */
    public static byte[] terminalNum2Arr(String terminalNum){
        if(terminalNum.length()<12) {
            terminalNum = String.format("%012d",Long.valueOf(terminalNum));
        }
        byte[] terminalArr= ByteBufUtil.decodeHexDump(terminalNum);
        return terminalArr;
    }
    /**
     * packet full command message
     * @param commandParams
     * @param bodyArr
     * @return
     */
    public static byte[] packetFullCommandMessage(CommandParams commandParams, byte[] bodyArr) {
        //Message length after excluding header and tail
        int contentLen = Jt808Constant.MSG_BASE_LENGTH-2 + bodyArr.length;
        //Message body length
        int msgBodyLen = bodyArr.length;
        //init message body excluding header and tail
        ByteBuf bodyBuf = ByteBufAllocator.DEFAULT.heapBuffer(contentLen);
        try {
            //Message ID
            bodyBuf.writeShort(commandParams.getMsgId());
            //The message body length of the message body attribute
            int msgBodyAttr = msgBodyLen;
            //Message Body Properties
            bodyBuf.writeShort(msgBodyAttr);
            //device Id
            bodyBuf.writeBytes(CommonUtil.terminalNum2Arr(commandParams.getDeviceId()));
            //Message serial number
            bodyBuf.writeShort(commandParams.getMsgFlowId());
            //message body
            if (msgBodyLen > 0) {
                bodyBuf.writeBytes(bodyArr);
            }
            //Check Code
            int checkCode = CommonUtil.xor(bodyBuf);
            bodyBuf.writeByte(checkCode);
            ByteBuf fullMessageBuf = Unpooled.buffer(bodyBuf.readableBytes()+2);
            fullMessageBuf.writeByte(Jt808Constant.MSG_HEAD_TAIL_FLAG);
            bodyBuf.readerIndex(0);
            Jt808PacketUtil.escape(fullMessageBuf, bodyBuf);
            fullMessageBuf.writeByte(Jt808Constant.MSG_HEAD_TAIL_FLAG);
            return ByteBufUtil.getBytes(fullMessageBuf);
        } catch (Exception e) {
            log.error("{}:message encoding exception,content:{}", commandParams.getDeviceId(), commandParams, e);
            return null;
        } finally {
            ReferenceCountUtil.release(bodyBuf);
        }
    }
}
